#include "MultiNet_Test.h"

#include "misc/MultiNet.h"
#include "misc/Event.h"
#include <Poco/Net/NetException.h>
#include <Poco/Net/NetworkInterface.h>
#include <iostream>
/*********************************************************/
std::string MultiNetTest::name()
{
	return("MultiNet");
}
/*********************************************************/
bool MultiNetTest::runUnitTests()
{
	bool result = true;
	
	if ( !cleanStartStopTest()) result = false;
	if ( !joinGroupTest()) result = false;
	if ( !joinDoubleGroupTest()) result = false;
	if ( !sendDataTest()) result = false;
	if ( !groupIPReturn()) result = false;
	if ( !doubleStartTest()) result = false;
	if ( !doubleStopTest()) result = false;
	if ( !idleStopTest()) result = false;
	if ( !eventResponseTest()) result = false;

	return( result ) ;
}
/*********************************************************/
bool MultiNetTest::idleStopTest()
{
	std::cout << "Running: idleStopTest()";
	std::cout.flush();
	try {
		Poco::Net::NetworkInterface::NetworkInterfaceList	netInt = Poco::Net::NetworkInterface::list();

		unsigned int i = 0;
		while (( netInt[i].name() != "wlan0" ) && ( netInt[i].name() != "eth0" )) {
			if ( i < netInt.size() ) {
				i++;
			} else {
				throw(std::logic_error("No test interface available"));
			}
		}
		MultiNet mNet(netInt[i].name());
		mNet.stop();
	} catch(Poco::Net::NetException& e) {
		std::cout << "... failed with exception: " << e.displayText() << std::endl;
		return( false );
	} catch(Poco::InvalidArgumentException& e) {
		std::cout << "... failed with exception: " << e.displayText() << std::endl;
		return( false );
	} catch(...) {
		std::cout << "... failed with unknown exception" << std::endl;
		return( false );
	}
	std::cout << "... success!" << std::endl;
	return( true );
}
/*********************************************************/
bool MultiNetTest::doubleStopTest()
{
	std::cout << "Running: doubleStopTest()";
	std::cout.flush();
	try {
		Poco::Net::NetworkInterface::NetworkInterfaceList	netInt = Poco::Net::NetworkInterface::list();

		unsigned int i = 0;
		while (( netInt[i].name() != "wlan0" ) && ( netInt[i].name() != "eth0" )) {
			if ( i < netInt.size() ) {
				i++;
			} else {
				throw(std::logic_error("No test interface available"));
			}
		}
		MultiNet mNet(netInt[i].name());
		mNet.start("TRAFFIC");
		mNet.stop();
		mNet.stop();
	} catch(Poco::Net::NetException& e) {
		std::cout << "... failed with exception: " << e.displayText() << std::endl;
		return( false );
	} catch(Poco::InvalidArgumentException& e) {
		std::cout << "... failed with exception: " << e.displayText() << std::endl;
		return( false );
	} catch(...) {
		std::cout << "... failed with unknown exception" << std::endl;
		return( false );
	}
	std::cout << "... success!" << std::endl;
	return( true );
}
/*********************************************************/
bool MultiNetTest::doubleStartTest()
{
	std::cout << "Running: doubleStartTest()";
	std::cout.flush();
	try {
		Poco::Net::NetworkInterface::NetworkInterfaceList	netInt = Poco::Net::NetworkInterface::list();

		unsigned int i = 0;
		while (( netInt[i].name() != "wlan0" ) && ( netInt[i].name() != "eth0" )) {
			if ( i < netInt.size() ) {
				i++;
			} else {
				throw(std::logic_error("No test interface available"));
			}
		}
		MultiNet mNet(netInt[i].name());
		mNet.start("TRAFFIC");
		mNet.start("TRAFFIC");
		mNet.stop();
	} catch(Poco::Net::NetException& e) {
		std::cout << "... failed with exception: " << e.displayText() << std::endl;
		return( false );
	} catch(Poco::InvalidArgumentException& e) {
		std::cout << "... failed with exception: " << e.displayText() << std::endl;
		return( false );
	} catch(...) {
		std::cout << "... failed with unknown exception" << std::endl;
		return( false );
	}
	std::cout << "... success!" << std::endl;
	return( true );
}
/*********************************************************/
bool MultiNetTest::cleanStartStopTest()
{
	std::cout << "Running: cleanStartStopTest()";
	std::cout.flush();
	try {
		Poco::Net::NetworkInterface::NetworkInterfaceList	netInt = Poco::Net::NetworkInterface::list();

		unsigned int i = 0;
		while (( netInt[i].name() != "wlan0" ) && ( netInt[i].name() != "eth0" )) {
			if ( i < netInt.size() ) {
				i++;
			} else {
				throw(std::logic_error("No test interface available"));
			}
		}
		MultiNet mNet(netInt[i].name());
		mNet.start("TRAFFIC");
		mNet.stop();
	} catch(Poco::Net::NetException& e) {
		std::cout << "... failed with exception: " << e.displayText() << std::endl;
		return( false );
	} catch(Poco::InvalidArgumentException& e) {
		std::cout << "... failed with exception: " << e.displayText() << std::endl;
		return( false );
	} catch(...) {
		std::cout << "... failed with unknown exception" << std::endl;
		return( false );
	}
	std::cout << "... success!" << std::endl;
	return( true );
}
/*********************************************************/
bool MultiNetTest::groupIPReturn()
{
	std::cout << "Running: groupIPReturn()";
	std::cout.flush();
	Poco::Net::NetworkInterface::NetworkInterfaceList	netInt = Poco::Net::NetworkInterface::list();
	unsigned int i = 0;
	while (( netInt[i].name() != "wlan0" ) && ( netInt[i].name() != "eth0" )) {
		if ( i < netInt.size() ) {
			i++;
		} else {
			throw(std::logic_error("No test interface available"));
		}
	}

	MultiNet net(netInt[i].name());
	net.start("TRAFFIC");
	net.joinGroup("239.0.0.1",12345);

	if ( net.getGroupIP() != "239.0.0.1" ) {
		std::cout << "... failed, got" << net.getGroupIP() << std::endl;
		return( false );
	}
	net.stop();
	std::cout << "... success!" << std::endl;
	return( true );
}
/*********************************************************/
bool MultiNetTest::sendDataTest()
{
	std::cout << "Running: sendDataTest()";
	std::cout.flush();
	try {
		Poco::Net::NetworkInterface::NetworkInterfaceList	netInt = Poco::Net::NetworkInterface::list();

		if ( netInt.size() == 1 ) {
			std::cout << "... Unable to test... only loopback interface available" << std::endl;
			return( true );
		}

		unsigned int i = 0;
		while (( netInt[i].name() != "wlan0" ) && ( netInt[i].name() != "eth0" )) {
			if ( i < netInt.size() ) {
				i++;
			} else {
				throw(std::logic_error("No test interface available"));
			}
		}

		MultiNet mNet(netInt[i].name());
		MultiNet mNet2(netInt[i].name());
		mNet.start("TRAFFIC");
		mNet2.start("TRAFFIC");
		mNet.joinGroup("239.0.0.1",12345);
		mNet2.joinGroup("239.0.0.1",12345);
		mNet.setLoopback(true);
		mNet2.setLoopback(false);

		// Send the message on the first interface & wait till the 2nd has received the message ( up to max 2.5 seconds )
		mNet.send("Hello World!");
		bool response = false;
		for ( i=0; i<25; i++ ) {
			if ( !mNet2.available() ) {
				usleep(100);
			} else {
				response = true;
				break;
			}
		}
		
		if ( !response ) {
			std::cout << "... failed, no data received on 2nd socket!" << std::endl;
			mNet.stop();
			mNet2.stop();
			return( false );
		}

		if ( std::string("Hello World!") != mNet2.pop() ) {
			std::cout << "... failed, data not identical" << std::endl;
			mNet.stop();
			mNet2.stop();
			return( false );
		} else {
			if ( i >= 24 ) {
				std::cout << "... succes, WARNING slow response on data reception in 2nd socket" << std::endl;
				mNet.stop();
				mNet2.stop();
				return( true );
			}
		}
		mNet.stop();
		mNet2.stop();

	} catch(Poco::Net::NetException& e) {
		std::cout << "... failed with exception: " << e.displayText() << std::endl;
		return( false );
	} catch(Poco::InvalidArgumentException& e) {
		std::cout << "... failed with exception: " << e.displayText() << std::endl;
		return( false );
	}
	std::cout << "... success!" << std::endl;
	return( true );
}
/*********************************************************/
bool MultiNetTest::eventResponseTest()
{
	std::cout << "Running: eventResponseTest()";
	std::cout.flush();
	try {
		Poco::Net::NetworkInterface::NetworkInterfaceList	netInt = Poco::Net::NetworkInterface::list();
		Event* event = Event::Instance("TRAFFIC");

		if ( netInt.size() == 1 ) {
			std::cout << "... Unable to test... only loopback interface available" << std::endl;
			return( true );
		}

		unsigned int i = 0;
		while (( netInt[i].name() != "wlan0" ) && ( netInt[i].name() != "eth0" )) {
			if ( i < netInt.size() ) {
				i++;
			} else {
				throw(std::logic_error("No test interface available"));
			}
		}

		MultiNet mNet(netInt[i].name());
		mNet.start("TRAFFIC");
		mNet.joinGroup("239.0.0.1",12345);
		mNet.setLoopback(true);
		mNet.send("Hello World!");
		event->wait();
		mNet.stop();

	} catch(Poco::Net::NetException& e) {
		std::cout << "... failed with exception: " << e.displayText() << std::endl;
		return( false );
	} catch(Poco::InvalidArgumentException& e) {
		std::cout << "... failed with exception: " << e.displayText() << std::endl;
		return( false );
	}
	std::cout << "... success!" << std::endl;
	return( true );
}
/*********************************************************/
bool MultiNetTest::joinDoubleGroupTest()
{
	std::cout << "Running: joinDoubleGroupTest()";
	std::cout.flush();
	try {
		Poco::Net::NetworkInterface::NetworkInterfaceList	netInt = Poco::Net::NetworkInterface::list();

		unsigned int i = 0;
		while (( netInt[i].name() != "wlan0" ) && ( netInt[i].name() != "eth0" )) {
			if ( i < netInt.size() ) {
				i++;
			} else {
				throw(std::logic_error("No test interface available"));
			}
		}


		MultiNet mNet(netInt[i].name());
		MultiNet mNet2(netInt[i].name());
		mNet.start("TRAFFIC");
		mNet2.start("TRAFFIC");
		mNet.joinGroup("239.0.0.1",12345);
		mNet2.joinGroup("239.0.0.1",12345);
		mNet.stop();
		mNet2.stop();
	} catch(Poco::Net::NetException& e) {
		std::cout << "... failed with exception: " << e.displayText() << std::endl;
		return( false );
	} catch(Poco::InvalidArgumentException& e) {
		std::cout << "... failed with exception: " << e.displayText() << std::endl;
		return( false );
	}
	std::cout << "... success!" << std::endl;
	return( true );
}
/*********************************************************/
bool MultiNetTest::joinGroupTest()
{
	std::cout << "Running: joinGroupTest()";
	std::cout.flush();
	try {
		Poco::Net::NetworkInterface::NetworkInterfaceList	netInt = Poco::Net::NetworkInterface::list();
		unsigned int i = 0;
		while (( netInt[i].name() != "wlan0" ) && ( netInt[i].name() != "eth0" )) {
			if ( i < netInt.size() ) {
				i++;
			} else {
				throw(std::logic_error("No test interface available"));
			}
		}

		MultiNet mNet(netInt[i].name());

		mNet.start("TRAFFIC");
		mNet.joinGroup("239.0.0.1",12345);
		mNet.stop();
	} catch(Poco::Net::NetException& e) {
		std::cout << "... failed with exception: " << e.displayText() << std::endl;
		return( false );
	} catch(Poco::InvalidArgumentException& e) {
		std::cout << "... failed with exception: " << e.displayText() << std::endl;
		return( false );
	}
	std::cout << "... success!" << std::endl;
	return( true );
}
/*********************************************************/
